import React from 'react';
import { act, fireEvent, render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import demoTest from '../../../tests/demoTest';
import mountTest from '../../../tests/mountTest';
import { createStartTouchEventObject } from '../../../tests/helpers/mockEvent';
import { defaultContext } from '../../context-provider';
import ImagePicker from '..';
import '@testing-library/jest-dom';

demoTest('image-picker');

mountTest(ImagePicker, 'ImagePicker');

const prefix = `${defaultContext.prefixCls}-image-picker`;
const imagePrefix = `${defaultContext.prefixCls}-image`;

const IMG_URL = 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_1.jpg';

const IMG_DATA =
    '';

const mockImgFile = new File([IMG_DATA], 'img.png', { type: 'image/png' });

describe('ImagePicker', () => {
    beforeEach(() => {
        jest.useFakeTimers();
        jest.spyOn(global, 'FileReader').mockImplementation(function () {
            this.readAsDataURL = jest.fn();
            this.onload = jest.fn();
            this.onerror = jest.fn();
        });
    });
    afterEach(() => {
        jest.useRealTimers();
        jest.restoreAllMocks();
    });
    it('ImagePicker renders correctly', () => {
        const { container } = render(<ImagePicker images={[]} />);
        expect(container.querySelectorAll(`.${prefix}-add`).length).toBe(1);
    });
    it('ImagePicker renders correctly', () => {
        const { container } = render(<ImagePicker images={[{ url: IMG_URL }, { url: IMG_URL }]} />);
        expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(2);
    });
    it('ImagePicker renders correctly', () => {
        const { container } = render(
            <ImagePicker images={[{ url: IMG_URL }, { url: IMG_URL }]} limit={1} />,
        );
        expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(1);
    });
    it('ImagePicker renders correctly', () => {
        const { container, rerender } = render(
            <ImagePicker images={[{ url: IMG_URL }, { url: IMG_URL }]} limit={1} />,
        );
        expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(1);
        rerender(<ImagePicker images={[]} limit={1} />);
        expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(0);
    });
    it('onChange listener correctly', () => {
        const onChange = jest.fn();
        const { container } = render(
            <ImagePicker images={[{ url: IMG_URL }]} onChange={onChange} />,
        );
        container.querySelector(`.${prefix}-close`);
        userEvent.click(container.querySelector(`.${prefix}-close`));
        expect(onChange.mock.calls.length).toBe(1);
    });
    it('upload correctly', async () => {
        function App() {
            const [images, setImages] = React.useState([]);
            return <ImagePicker images={images} onChange={setImages} />;
        }
        const { container } = render(<App />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, mockImgFile);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(1);
        });
    });
    it('custom upload', async () => {
        function App() {
            async function mockUpload() {
                return {
                    url: IMG_DATA,
                };
            }
            const [images, setImages] = React.useState([]);
            return <ImagePicker images={images} onChange={setImages} upload={mockUpload} />;
        }
        const { container } = render(<App />);
        const selectors = container.querySelectorAll(`.${prefix}-add`);
        const inputs = container.querySelectorAll('input');
        await userEvent.click(selectors[0]);
        await userEvent.upload(inputs[0], mockImgFile);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(1);
        });
    });
    it('upload maxSize', async () => {
        function App({ onMaxSizeExceed }) {
            const [images, setImages] = React.useState([]);
            return (
                <ImagePicker
                    maxSize={1}
                    images={images}
                    onChange={setImages}
                    onMaxSizeExceed={onMaxSizeExceed}
                />
            );
        }
        const handleMaxSizeExceed = jest.fn();
        const { container } = render(<App onMaxSizeExceed={handleMaxSizeExceed} />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, mockImgFile);
        await waitFor(() => {
            expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(0);
        });
        await waitFor(() => {
            expect(handleMaxSizeExceed).toBeCalledTimes(1);
        });
    });
    it('upload limit', async () => {
        function App({ onLimitExceed }) {
            const [images, setImages] = React.useState([]);
            return (
                <ImagePicker
                    multiple
                    limit={1}
                    images={images}
                    onChange={setImages}
                    onLimitExceed={onLimitExceed}
                />
            );
        }
        const handlLimitExceed = jest.fn();
        const { container } = render(<App onLimitExceed={handlLimitExceed} />);
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        const input = container.querySelector('input');
        await userEvent.upload(input, [mockImgFile, mockImgFile, mockImgFile]);
        const reader = FileReader.mock.instances[0];
        reader.onload({ target: { result: 'foo' } });
        await waitFor(() => {
            expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(1);
        });
        await waitFor(() => {
            expect(handlLimitExceed).toBeCalledTimes(1);
        });
    });
    it('click image correctly', () => {
        const handleClick = jest.fn();
        const { container } = render(
            <ImagePicker images={[{ url: IMG_URL }]} onClick={handleClick} />,
        );
        userEvent.click(container.querySelector(`.${imagePrefix}`));
        expect(handleClick).toBeCalledTimes(1);
    });
    it('press image correctly', () => {
        const handleLongPress = jest.fn();
        const { container } = render(
            <ImagePicker images={[{ url: IMG_URL }]} onLongPress={handleLongPress} />,
        );
        act(() => {
            fireEvent.touchStart(
                container.querySelector(`.${prefix}-image-container`),
                createStartTouchEventObject({ x: 0, y: 0 }),
            );
            jest.advanceTimersByTime(1000);
        });
        expect(handleLongPress).toBeCalledTimes(1);
    });
    it('selectAdapter', async () => {
        const handleMaxSizeExceed = jest.fn();
        const handleLimitExceed = jest.fn();
        function App({ onMaxSizeExceed, onLimitExceed }) {
            const [images, setImages] = React.useState([{ url: IMG_URL }, { url: IMG_URL }]);
            const selectAdapter = () => {
                return new Promise(resolve => {
                    const files = [
                        {
                            name: '11vnpmryrl4.jpeg',
                            size: 789020,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_1.jpg',
                        },
                        {
                            name: '11vnpmryrl2.jpeg',
                            size: 7820,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_2.jpg',
                        },
                        {
                            name: '11vnpmryrl1.jpeg',
                            size: 7820,
                            type: 'image/jpeg',
                            url: 'http://sf1-cdn-tos.toutiaostatic.com/obj/arco-mobile/_static_/large_image_3.jpg',
                        },
                    ];
                    resolve({ files });
                });
            };
            return (
                <ImagePicker
                    images={images}
                    onChange={setImages}
                    selectAdapter={selectAdapter}
                    limit={3}
                    maxSize={100}
                    multiple
                    onMaxSizeExceed={onMaxSizeExceed}
                    onLimitExceed={onLimitExceed}
                />
            );
        }
        const { container } = render(
            <App onMaxSizeExceed={handleMaxSizeExceed} onLimitExceed={handleLimitExceed} />,
        );
        const selector = container.querySelector(`.${prefix}-add`);
        await userEvent.click(selector);
        await waitFor(() => {
            expect(container.querySelectorAll(`.${imagePrefix}`).length).toBe(3);
        });
        await waitFor(() => {
            expect(handleMaxSizeExceed).toBeCalledTimes(1);
        });
        await waitFor(() => {
            expect(handleLimitExceed).toBeCalledTimes(1);
        });
    });
});
